package com.github.cakin.shiro.chapter20.realm;

import com.github.cakin.shiro.chapter20.codec.HmacSHA256Utils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.Map;

/**
 * @className: StatelessRealm
 * @description: 用于认证的 Realm，获得无状态认证的信息
 * @date: 2020/5/29
 * @author: cakin
 */
public class StatelessRealm extends AuthorizingRealm {
    @Override
    public boolean supports( AuthenticationToken token ) {
        // 仅支持StatelessToken类型的Token
        return token instanceof StatelessToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals ) {
        // 根据用户名查找角色，请根据需求实现
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRole("admin");
        return authorizationInfo;
    }
    /**
     * 功能描述：获得认证信息
     *  首先根据客户端传入的用户名获取相应的密钥，然后使用密钥对请求参数生成服务器端的消息摘要；
     *  后续流程会对客户端的消息摘要进行匹配；如果匹配说明是合法客户端传入的；否则是非法的。
     * @author cakin
     * @date 2020/5/29
     * @param token 用户身份信息
     * @return AuthenticationInfo 服务端返回认证信息，供后面的流程匹配
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token ) throws AuthenticationException {
        // 转 token 为 StatelessToken 类型
        StatelessToken statelessToken = (StatelessToken) token;
        // 得到用户名
        String username = statelessToken.getUsername();
        // 根据用户名获取密钥（和客户端的一样）
        String key = getKey(username);
        // 在服务器端生成客户端参数消息摘要
        Map<String, ?> params = statelessToken.getParams();
        /**
         * 服务端调用前的值
         key = "dadadswdewq2ewdwqdwadsadasd"
         value = {char[27]@6034}
         hash = 0
         params = {HashMap@6026}  size = 3
         "param1" -> {String[2]@6041}
         key = "param1"
         value = {String[2]@6041}
         0 = "param11"
         1 = "param12"
         "username" -> {String[1]@6043}
         key = "username"
         value = {String[1]@6043}
         0 = "admin"
         "param2" -> {String[1]@6045}
         key = "param2"
         value = {char[6]@6048}
         hash = -995428027
         value = {String[1]@6045}
         0 = "param2"
         value = {char[6]@6050}
         hash = 0
         */
        String serverDigest = HmacSHA256Utils.digest(key, params);
        // 打印客户端传过来的消息摘要
        System.out.println(statelessToken.getClientDigest());
        // 打印服务端传过来的消息摘要
        System.out.println(serverDigest);
        // 返回认证信息，后面的流程会进行客户端消息摘要和服务器端消息摘要的匹配
        return new SimpleAuthenticationInfo(
                username,
                serverDigest,
                getName());
    }

    /**
     * 功能描述：得到密钥，此处硬编码一个
     *
     * @param username 用户名
     * @return String 密钥
     * @author cakin
     * @date 2020/5/29
     * @description:
     */
    private String getKey( String username ) {
        if ("admin".equals(username)) {
            return "dadadswdewq2ewdwqdwadsadasd";
        }
        return null;
    }
}
